--[[
Combat.lua
A miniature duelling system.
Version 0.1
Based on an idea from VoidWare, written for the lua programming language by Tyrone.

-------------------------
Changelog:
0.1
-Basic functionality.  This one is gonna get huge like xbox folks!
]]

--Spell definitions:
FLAMETHROWING =   "0 - Flamethrowing - 15 mana - 5s - Launches a ball of flame at the target for 6-8 damage per rank."
FREEZINGWIND =    "1 - Freezing Wind - 30 mana - 5s - Surrounds the target in a freezing cold wind slowing down their cast time by 2 for 1 minute and dealing 4-6 damage per rank."
ARCANELANCE =     "2 - Arcane Lance - 20 mana - 5s - Hurls an ethereal spear at the target dealing 6-8 damage per rank, cutting through armour."
DIVINEFOCUS =     "3 - Divine Focus - 25 mana - 8s - Increases mana regeneration by a factor of 1.5 for one minute."
EXPLOSIVECHARGE = "4 - Explosive Charge - 15 mana - 5s - Explodes on the target for 8-10 damage per rank, but has a chance to damage self for 4-5 per rank."
MENDINGPRAYER =   "5 - Mending Prayer - 20 mana - 6s - Heals target for 6-10 HP per rank."
ARMOURPADDING =   "6 - Armour Padding - 15 mana - 8s - Doubles armour rating for one minute."
WRATHOFTHOR =     "7 - Wrath of Thor - 50 mana - 15s - Target gets struck by a bolt of lightning for 12-14 damage per rank, and 2-4 mana per rank.  Has a very long cast time and a long cool down."
TIMESTOP =        "8 - Time Stop - 50 mana - 15s - Completely prevents the target from moving for one minute.  Has a very long cast time and a long cool down."
DEVOURINGPLAGUE = "9 - Devouring Plague - 50 mana - 15s - Target gets inflicted by a fatal disease, dealing 3 damage per rank for every move they make.  Has a very long cast time and a long cool down."

--Constants--
--_,SECURITY = VH:GetConfig("config", "hub_security")
PATHTOSAVEFILE = "/etc/verlihub/scripts/combat.sav"
BASE_HP_REGEN = 5       --per 5 second HP regen rate outside combat
BASE_MANA_REGEN = 5   --per 5 second Mana regen rate
BASE_HP = 60            --HP at level 1
BASE_MANA = 100         --Mana at level 1
BASE_ARMOUR = 5         --Armour at level 1
NEWLINE = string.format("\n")
-------------

--Tables--
inCombat = {}
hp = {}
mana = {}
currentHp = {}
currentMana = {}
armour = {}
manaRegen = {}
hpRegen = {}
castSpeed = {}
level = {}
experience = {}
hasPlague = {}
hasTimeStop = {}
hasSlowed = {}
hasPadding = {}
hasFocus = {}
challenged = {}
cooldowns = {}
challengeCoolDown = {}
isTheChallenger = {}
countdown = {}
castTimer = {}
lastBattles = {}
spellCasting = {}
tick = {}
wins = {}
losses = {}

spellCosts = {}; spellTime = {}; spellName = {};
spellCosts[0] = 15; spellTime[0] = 5; spellName[0] = "Flamethrowing"
spellCosts[1] = 30; spellTime[1] = 5; spellName[1] = "Freezing Wind"
spellCosts[2] = 20; spellTime[2] = 5; spellName[2] = "Arcane Lance"
spellCosts[3] = 25; spellTime[3] = 8; spellName[3] = "Divine Focus"
spellCosts[4] = 15; spellTime[4] = 5; spellName[4] = "Explosive Charge"
spellCosts[5] = 20; spellTime[5] = 6; spellName[5] = "Mending Prayer"
spellCosts[6] = 15; spellTime[6] = 8; spellName[6] = "Armour Padding"
spellCosts[7] = 50; spellTime[7] = 15; spellName[7] = "Wrath of Thor"
spellCosts[8] = 50; spellTime[8] = 15; spellName[8] = "Time Stop"
spellCosts[9] = 50; spellTime[9] = 15; spellName[9] = "Devouring Plague"
----------

--VerliHub Base Functions--
function VH_OnParsedMsgChat(nick, data)
	--Find which commands people are calling
	if (string.find(data, "^%.challenge")) then --Challenge another user
		--If their challenged table value is nil, well it should actually be zero
		if (challenged[nick] == nil) then challenged[nick] = 0 end
		
		--You can only challenge someone if you aren't already challenging someone
		--Get the victim out of the string
		_,_,victim = string.find(data, "%s(.+)")
		
		if (victim == nil) then
			--the user simply typed .challenge
			showHelp(nick)
			return 0
		end
		
		if (victim == "help") then
			--the user typed .challenge help
			showHelp(nick)
			return 0
		end
		
		if (challenged[nick] ~= 0) then
			SendMessageToUser("You have already challenged someone.  ("..challenged[nick]..")",nick)
			return 0
		end
		
		--You cannot challenge yourself!
		if (victim == nick) then
			SendMessageToUser("You can't challenge yourself to a duel!",nick)
		end
		
		--Check if the victim is online
		if (UserIsOnline(victim) == false) then
			SendMessageToUser("The user: "..victim.." is not online.", nick)
			return 0
		end
		
		--If the victim's challenged table is nil, well it should be zero
		if (challenged[victim] == nil) then challenged[victim] = 0 end
		
		--Check if the victim has already been challenged
		if (challenged[victim] ~= 0) then
			--Victim has already been challenged.
			SendMessageToUser("The user: "..victim.." has already been challenged to a duel.", nick)
			return 0
		end
		
		--If the challenger's inCombat table value is nil, it should be zero
		if (inCombat[nick] == nil) then inCombat[nick] = false end
		
		--If the victim's inCombat table value is nil, it should be zero
		if (inCombat[victim] == nil) then inCombat[victim] = false end
		
		--Check if the challenger is already in combat
		if (inCombat[nick] == true) then
			--Challenger is already in the process of fighting someone
			SendMessageToUser("You can't challenge another person while you're fighting someone else.", nick)
			return 0
		end
		
		--levels should not be nil
		if (level[nick] == nil) then level[nick] = 1 end
		if (level[victim] == nil) then level[victim] = 1 end
		
		--Challenger and challenged cannot be more than three levels apart
		if ((level[nick] - level[victim] > 3) or (level[victim] - level[nick] > 3)) then
			SendMessageToUser("You can't challenge a person who is more than three levels above or below you.", nick)
			return 0
		end
		
		--Initialise tables if the person has never duelled before
		if (hp[nick] == nil) then hp[nick] = BASE_HP end
		if (hp[victim] == nil) then hp[victim] = BASE_HP end
		if (mana[nick] == nil) then mana[nick] = BASE_MANA end
		if (mana[victim] == nil) then mana[victim] = BASE_MANA end
		if (armour[nick] == nil) then armour[nick] = BASE_ARMOUR end
		if (armour[victim] == nil) then armour[victim] = BASE_ARMOUR end
		if (hpRegen[nick] == nil) then hpRegen[nick] = BASE_HP_REGEN end
		if (hpRegen[victim] == nil) then hpRegen[victim] = BASE_HP_REGEN end
		if (manaRegen[nick] == nil) then manaRegen[nick] = BASE_MANA_REGEN end
		if (manaRegen[victim] == nil) then manaRegen[victim] = BASE_MANA_REGEN end
		if (currentHp[nick] == nil) then currentHp[nick] = hp[nick] end
		if (currentHp[victim] == nil) then currentHp[victim] = hp[victim] end
		if (currentMana[nick] == nil) then currentMana[nick] = mana[nick] end
		if (currentMana[victim] == nil) then currentMana[victim] = mana[victim] end
		if (tick[nick] == nil) then tick[nick] = 5 end
		if (tick[victim] == nil) then tick[victim] = 5 end
		
		--Set the challenger and challenged's challenged value to eachother
		challenged[nick] = victim
		challenged[victim] = nick
		
		--Tell the challenged about the duel
		SendMessageToUser(victim..": YOU HAVE BEEN CHALLENGED TO A DUEL BY: "..string.upper(nick).."!"..NEWLINE.."-- Type .accept to start a duel with them.", victim)
		--Tell the challenger about the duel
		SendMessageToUser("YOU HAVE CHALLENGED "..string.upper(victim).." TO A DUEL."..NEWLINE.."-- You must wait for them to accept.  This invitation will expire in 60 seconds.", nick)
		challengeCoolDown[nick] = 60
		challengeCoolDown[victim] = 60
		isTheChallenger[nick] = true
		isTheChallenger[victim] = false
		return 0
	elseif (string.find(data, "^.accept")) then --Accept a challenge
		--challenged table should not be nil
		if (challenged[nick] == nil) then challenged[nick] = 0 end
		
		--check to see if this person has been challenged
		if (challenged[nick] == 0) then
			SendMessageToUser("You haven't been issued a challenge.  If you want to challenge someone, use .challenge username.", nick)
			return 0
		end
		
		--check to see if this person is the challenged
		if (isTheChallenger[nick] == true) then
			SendMessageToUser("You're the one who issued the challenge!  They are the one who needs to .accept!", nick)
			return 0
		end
		
		--Start the duel in five seconds.
		SendMessageToUser("Duel starting in:", nick)
		SendMessageToUser("Duel starting in:", challenged[nick])
		countdown[nick] = 5
		countdown[challenged[nick]] = 5
		challengeCoolDown[nick] = 0
		challengeCoolDown[challenged[nick]] = 0
		return 0
		
	elseif (string.find(data, "^.cast")) then --Cast a spell on another user
		--if they just typed .cast without anything else, display help
		--_,_,instr = string.find(data, "^.cast%s(.+)")
		--_,_,victim = string.find(instr, "(.+)%s")
		local _,_,spell = string.find (data, "%s(%d+)")
		
		if (spell == nil) then
			showHelp(nick)
			return 0
		end
		
		--check if the person is in combat
		if (inCombat[nick] ~= true) then
			SendMessageToUser("You're not in combat with anyone yet.  Use .challenge to challenge someone.",nick)
			return 0
		end
		
		--couldn't hurt to check for this
		if (challenged[nick] == nil) or (challenged[nick] == 0) then
			SendMessageToUser("This duel has become bugged.",nick)
			return 0
		end
		
		spell = math.floor(tonumber(spell))
		
		--check if the spell they typed is valid
		if (spell > 9) or (spell < 0) then
			SendMessageToUser("Please enter a spell ID as shown in .spells.",nick)
			return 0
		end
		
		--once again remove the nil
		if (castTimer[nick] == nil) then castTimer[nick] = 0 end
		if (cooldowns[nick] == nil) then 
			cooldowns[nick] = {}
		end
		
		--check to see if they are already casting
		if (castTimer[nick] > 0) then
			SendMessageToUser("You're already casting a spell!  Wait for that one to finish first!",nick)
			return 0
		end
		
		--check to see if the spell they are trying to cast is on cooldown
		local cooldown = cooldowns[nick]
		if (cooldown[spell] == nil) then cooldown[spell] = 0 end
		if (cooldown[spell] > 0) then
			SendMessageToUser("That spell is on cooldown.  It will be ready for use in "..cooldown[spell].." seconds.",nick)
			return 0
		end
		cooldowns[nick] = cooldown
		
		--check to see if they have enough mana
		if (currentMana[nick] < spellCosts[spell]) then
			SendMessageToUser("You do not have enough mana.  You have: "..string.format("%g",currentMana[nick]).." and you need: "..spellCosts[spell],nick)
			return 0
		end
		
		--check to see if they have Time Stop
		if (hasTimeStop[nick] == nil) then hasTimeStop[nick] = 0 end
		if (hasTimeStop[nick] ~= 0) then
			SendMessageToUser("You've been time stopped!  You can't move for another "..hasTimeStop[nick].." seconds.",nick)
			return 0
		end
		
		--castSpeed should not be nil at this point
		if (castSpeed[nick] == nil) then castSpeed[nick] = 1 end
		
		--Let's do it!
		SendMessageToUser("Casting spell: "..spellName[spell].."...",nick)
		spellCasting[nick] = spell
		currentMana[nick] = currentMana[nick] - spellCosts[spell]
		castTimer[nick] = math.ceil(spellTime[spell] / castSpeed[nick])
		return 0
			
	elseif (string.find(data, "^.cooldowns")) then--Check cooldowns
	
	elseif (string.find(data, "^.status")) then--Check HP, mana and status conditions
		--Initialise values if the person has never duelled before
		if (hp[nick] == nil) then hp[nick] = BASE_HP end
		if (mana[nick] == nil) then mana[nick] = BASE_MANA end
		if (armour[nick] == nil) then armour[nick] = BASE_ARMOUR end
		if (hpRegen[nick] == nil) then hpRegen[nick] = BASE_HP_REGEN end
		if (manaRegen[nick] == nil) then manaRegen[nick] = BASE_MANA_REGEN end
		if (currentHp[nick] == nil) then currentHp[nick] = hp[nick] end
		if (currentMana[nick] == nil) then currentMana[nick] = mana[nick] end
		if (tick[nick] == nil) then tick[nick] = 5 end
		
		SendMessageToUser(NEWLINE.."-- HP: "..currentHp[nick].."/"..hp[nick]..NEWLINE.."-- Mana: "..currentMana[nick].."/"..mana[nick]..
						  NEWLINE.."-- Armour: "..armour[nick]..NEWLINE.."-- HP Regen: "..hpRegen[nick].."HP/5sec"..
						  NEWLINE.."-- Mana Regen: "..manaRegen[nick].."HP/5sec",nick)
		return 0
	elseif (string.find(data, "^.spells")) then--List spells and spell numbers
		SendMessageToUser(FLAMETHROWING, nick)
		SendMessageToUser(FREEZINGWIND, nick)
		SendMessageToUser(ARCANELANCE, nick)
		SendMessageToUser(DIVINEFOCUS, nick)
		SendMessageToUser(EXPLOSIVECHARGE, nick)
		SendMessageToUser(MENDINGPRAYER, nick)
		SendMessageToUser(ARMOURPADDING, nick)
		SendMessageToUser(WRATHOFTHOR, nick)
		SendMessageToUser(TIMESTOP, nick)
		SendMessageToUser(DEVOURINGPLAGUE, nick)
		return 0
	else --This isn't a combat message
	end
	return 1
end

function VH_OnTimer()
	--Do an update on everyone's cooldowns
	updateCooldowns()
	updateSpellCasts()
	updateTick()
	return 1
end

function VH_OnCloseConn(ip)
	return 1
end

function VH_OnNewConn(ip)
	return 1
end

function VH_OnUserLogin(nick)
	return 1
end

function VH_OnUserLogout(nick)
	if (countdown[nick] > 0) then
		SendMessageToUser("The other player forfeit before starting.",challenged[nick])
		countdown[nick] = 0
		countdown[challenged[nick]] = 0
		challenged[nick] = 0
		challenged[challenged[nick]] = 0
		return 1
	end

	if (inCombat[nick] == true) then
		defeat(challenged[nick], nick)
		return 1
	end
	
	if ((challenged[nick] ~= nil) or (challenged[nick] ~= 0)) then
		challenged[nick] = 0
		challengeCoolDown[nick] = 0
	end
	
	return 1
end
---------------------------

--Very low level functions, these assume input will be perfect--
function castSpellOnUser(nick, spell, rank)
	local damage = 0
	local chanceToMiss = 0
	local caster = challenged[nick]
	--Flamethrowing
	if (spell == 0) then
		damage = math.random(6.0 * rank, 8.0 * rank)
		damage = damage * math.exp(-0.0025646647 * armour[nick])
		
		chanceToMiss = math.random(0,9)
		if (chanceToMiss ~= 9) then
			currentHp[nick] = currentHp[nick] - damage
			SendMessageToUser(caster.."'s "..spellName[spell].." hits you for "..string.format("%g",damage).." damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", nick)
			SendMessageToUser("Your "..spellName[spell].." hits "..nick.." for "..string.format("%g",damage).. " damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", caster)
		else
			SendMessageToUser(caster.."'s "..spellName[spell].." misses you.", nick)
			SendMessageToUser("Your "..spellName[spell].." misses "..nick..".", caster)
		end
	
	--Freezing wind
	elseif (spell == 1) then
		damage = math.random(6.0 * rank, 8.0 * rank)
		damage = damage * math.exp(-0.0025646647 * armour[nick])
		chanceToMiss = math.random(0,9)
		if (chanceToMiss ~= 9) then
			currentHp[nick] = currentHp[nick] - damage
			SendMessageToUser(caster.."'s "..spellName[spell].." hits you for "..string.format("%g",damage).." damage.  You are slowed.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", nick)
			SendMessageToUser("Your "..spellName[spell].." hits "..nick.." for "..string.format("%g",damage).. " damage.  They are slowed.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", caster)
			--whoa this shouldn't stack!
			if (hasSlowed[nick] == nil) then hasSlowed[nick] = 0 end
			if (hasSlowed[nick] == 0) then
				castSpeed[nick] = castSpeed[nick] / 2
			end
			hasSlowed[nick] = 60
		else
			SendMessageToUser(caster.."'s "..spellName[spell].." misses you.", nick)
			SendMessageToUser("Your "..spellName[spell].." misses "..nick..".", caster)
		end
		
	--Arcane lance
	elseif (spell == 2) then
		damage = math.random(6.0 * rank, 8.0 * rank)
		chanceToMiss = math.random(0,8) --slightly more likely to miss with this
		if (chanceToMiss ~= 8) then
			currentHp[nick] = currentHp[nick] - damage
			SendMessageToUser(caster.."'s "..spellName[spell].." pierces your armour for "..string.format("%g",damage).." damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", nick)
			SendMessageToUser("Your "..spellName[spell].." pierces "..nick.."'s armour for "..string.format("%g",damage).. " damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", caster)
		else
			SendMessageToUser(caster.."'s "..spellName[spell].." misses you.", nick)
			SendMessageToUser("Your "..spellName[spell].." misses "..nick..".", caster)
		end
	--Divine focus
	elseif (spell == 3) then
		if (hasFocus[caster] == nil) then hasFocus[caster] =  0 end
		if (hasFocus[caster] == 0) then
			manaRegen[caster] = manaRegen[caster] * 1.5
		end
		hasFocus[caster] = 60
		SendMessageToUser("You cast "..spellName[spell].." on yourself.  Your mana regen increases by a factor of 1.5.", caster)
		SendMessageToUser(caster.." casts "..spellName[spell].." on themselves.  Their mana regen increases.", nick)
	--Explosive charge
	elseif (spell == 4) then
		damage = math.random(8.0 * rank, 10.0 * rank)
		damage = damage * math.exp(-0.0025646647 * armour[nick])
		chanceToMiss = math.random(0,6)
		if (chanceToMiss == 5) then
			damage = damage * 2
			currentHp[nick] = currentHp[nick] - damage
			SendMessageToUser(caster.."'s "..spellName[spell].." EXPLODES in your face for "..string.format("%g",damage).." damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", nick)
			SendMessageToUser("Your "..spellName[spell].." EXPLODES in "..nick.."'s face for "..string.format("%g",damage).. " damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", caster)
		elseif (chanceToMiss == 6) then
			currentHp[caster] = currentHp[caster] - damage
			SendMessageToUser(caster.."'s "..spellName[spell].." blows up in their own face for "..string.format("%g",damage).." damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[caster]..")", nick)
			SendMessageToUser("Your "..spellName[spell].." blows up in your face for "..string.format("%g",damage).." damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[caster]..")", caster)
		else
			currentHp[nick] = currentHp[nick] - damage
			SendMessageToUser(caster.."'s "..spellName[spell].." detonates in your face for "..string.format("%g",damage).." damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", nick)
			SendMessageToUser("Your "..spellName[spell].." detonates in "..nick.."'s face for "..string.format("%g",damage).. " damage.  ("..string.format("%g",currentHp[nick]).."/"..hp[nick]..")", caster)
		end
	--Mending prayer
	elseif (spell == 5) then
		damage = math.random(6.0 * rank, 10.0 * rank)
		currentHp[caster] = currentHp[caster] + damage
		if (currentHp[caster] > hp[caster]) then currentHp[caster] = hp[caster] end
		SendMessageToUser("You heal yourself for "..string.format("%g",damage).."HP.",caster)
		SendMessageToUser(caster.." heals themselves for "..string.format("%g",damage).."HP.",nick)
	--Armour padding
	elseif (spell == 6) then
		if (hasPadding[caster] == nil) then hasPadding[caster] =  0 end
		if (hasPadding[caster] == 0) then
			armour[caster] = armour[caster] * 2
		end
		hasPadding[caster] = 60
		SendMessageToUser("You cast "..spellName[spell].." on yourself.  Your armour doubles.", caster)
		SendMessageToUser(caster.." casts "..spellName[spell].." on themselves.  Their armour doubles.", nick)
	--Wrath of Thor
	elseif (spell == 7) then
		SendMessageToUser("BL2U THIS ISN'T IMPLEMENTED YET.", caster)
	--Time stop
	elseif (spell == 8) then
		SendMessageToUser("BL2U THIS ISN'T IMPLEMENTED YET.", caster)
	--Devouring plague
	elseif (spell == 9) then
		SendMessageToUser("BL2U THIS ISN'T IMPLEMENTED YET.", caster)
	end
	
	--Check if we've killed them
	if (currentHp[nick] <= 0) then
		defeat(caster, nick)
		return nil
	end
	
	--Now check if it's necessary to apply devouring plague damage
	if (hasPlague[caster] == nil) then hasPlague[caster] = 0 end
	if (hasPlague[caster] > 0) then
		local plagueDmg = 3
		hp[caster] = hp[caster] - plagueDmg
		SendMessageToUser("You take "..plagueDmg.." damage from Devouring Plague.", caster)
	end
	
	--Check if we've been killed
	if (currentHp[caster] <= 0) then
		defeat(nick, caster)
	end
end

function defeat(victorious, defeated)
	currentHp[defeated] = 1
	SendMessageToHub(victorious.." has defeated "..defeated.." in a duel!")
	inCombat[victorious] = false
	inCombat[defeated] = false
	isTheChallenger[victorious] = nil
	isTheChallenger[defeated] = nil
	castTimer[victorious] = nil
	castTimer[defeated] = nil
	spellCasting[victorious] = nil
	spellCasting[defeated] = nil
	hasTimeStop[victorious] = nil
	hasTimeStop[defeated] = nil
	challenged[victorious] = nil
	challenged[defeated] = nil
end

function showHelp(nick)
	SendMessageToUser("Usage: ", nick)
	DisplayHelpMessage("challenge", "help", "Shows this message.", nick)
	DisplayHelpMessage("challenge", "<username>", "Challenges user to a duel.", nick)
	DisplayHelpMessage("accept", "", "Accepts a duel challenge.", nick)
	DisplayHelpMessage("cast", "<SpellID>", "Casts a spell on a user.", nick)
	DisplayHelpMessage("cooldowns", "", "Lists all your spells and how many seconds you have to wait before you can cast them again.", nick)
	DisplayHelpMessage("forfeit", "", "Quits a currently running duel with a defeat.  You can also log out to achieve the same effect.", nick)
	DisplayHelpMessage("status", "", "Lists your current HP, mana, and any afflictions.", nick)
	DisplayHelpMessage("spells", "", "Displays a list of Spell IDs.", nick)
end

function updateCooldowns()
	--First thing we should worry about is challenge cooldowns
	for nick,time in pairs(challengeCoolDown) do
		if (time > 0) then
			challengeCoolDown[nick] = challengeCoolDown[nick] - 1
			
			if (challengeCoolDown[nick] == 0) then
				SendMessageToUser("Your challenge invitation has expired.", nick)
				challenged[nick] = 0
			end
		end
	end
	
	--Next we should look to see if there are any countdowns going on
	for nick,time in pairs(countdown) do
		if (time > 0) then
			SendMessageToUser(time, nick)
			countdown[nick] = countdown[nick] - 1
			
			if (countdown[nick] == 0) then
				SendMessageToUser("YOUR DUEL HAS STARTED.",nick)
				inCombat[nick] = true
			end
		end
	end
	
	--Lets deal with status conditions now
	for nick,time in pairs(hasSlowed) do
		if (time > 0) then
			hasSlowed[nick] = time - 1
			
			if (hasSlowed[nick] == 0) then
				castSpeed[nick] = castSpeed[nick] * 2
				SendMessageToUser("Your slow has worn off.",nick)
			end
		end
	end
	
	for nick,time in pairs(hasTimeStop) do
		if (time > 0) then
			hasTimeStop[nick] = time - 1
			
			if (hasTimeStop[nick] == 0) then
				SendMessageToUser("Your Time Stop has worn off.",nick)
			end
		end
	end
	
	for nick,time in pairs(hasPadding) do
		if (time > 0) then
			hasPadding[nick] = time - 1
			if (hasPadding[nick] == 0) then
			armour[nick] = armour[nick] / 2
			SendMessageToUser("Your Armour Padding has worn off.",nick)
		end
		end
	end
	
	for nick,time in pairs(hasFocus) do
		if (time > 0) then
			hasFocus[nick] = time - 1
			if (hasFocus[nick] == 0) then
				manaRegen[nick] = manaRegen[nick] / 1.5
				SendMessageToUser("Your Divine Focus has worn off.",nick)
			end
		end
	end
end

function updateSpellCasts()
	for nick,time in pairs(castTimer) do
		if (time > 0) then
			SendMessageToUser(time, nick)
			castTimer[nick] = castTimer[nick] - 1
			
			if (castTimer[nick] == 0) then
				--We should probably go ahead and cast that spell now
				castSpellOnUser(challenged[nick], spellCasting[nick], 1)
			end
		end
	end
end

function updateTick()
	for nick,time in pairs(tick) do
		if (time > 0) then
			tick[nick] = tick[nick] - 1
			
			if (tick[nick] == 0) then
				if (inCombat[nick] == false) then
					currentHp[nick] = currentHp[nick] + hpRegen[nick]
				end
				currentMana[nick] = currentMana[nick] + manaRegen[nick]
				
				if (currentHp[nick] > hp[nick]) then currentHp[nick] = hp[nick] end
				if (currentMana[nick] > mana[nick]) then currentMana[nick] = mana[nick] end
				tick[nick] = 5
			end
		end
	end
end
----------------------------------------------------------------

--Input/Output--
function saveToDisk()
	--[[Example output file structure
	Aethereal
	5		<-- Level
	560		<-- Experience
	10		<-- Wins
	5		<-- Losses
	]]
	
end

function loadFromDisk()

end
----------------

--The following is the contents of common.lua until I can work out why require() is being so homo--
_,bot_name = VH:GetConfig("config", "hub_security")
--SendMessageToHub
--Sends a message to the entire hub from a user.  If "from" parameter is
--neglected, the message will be sent from hub_security.
function SendMessageToHub(data, from)
	if (from == nil) then
		--Send it from hub security
		from = bot_name
	end
	return VH:SendDataToAll("<"..from.."> "..data.."|",0,10)
end

--SendMessageToUser
--Sends a message to a specific user in mainchat.  If "nick" parameter is
--neglected, the message will be sent to the whole hub.  If the "from" parameter
--is neglected, the message will be sent from hub_security.
function SendMessageToUser(data, nick, from)
	if (from == nil) then
		--Send it from hub security.
		from = bot_name
	end
	
	if (nick == nil) then
		--Send it to the whole hub.
		return VH:SendDataToAll("<"..from.."> "..data.."|",0,10)
	end
	
	return VH:SendDataToUser("<"..from.."> "..data.."|", nick)
end

function SendPrivateMessageToUser(user, data, from)
    return VH:SendDataToUser("$To: "..user.." From: "..from.." $<"..from.."> "..data.."|", user);
end

function DisplayHelpMessage(cmdname, cmd, msg, nick)
    SendMessageToUser("        ."..cmdname.." "..cmd, nick, bot_name)
    SendMessageToUser("        "..msg, nick, bot_name)
end

function UserClass(nick)
	res, class = VH:GetUserClass(nick)
	if res and class then return class else return 0 end
end

function UserIsOnline(nick)
	result, sIP = VH:GetUserIP(nick)
	if (string.len(sIP) < 7) then
		return false
	else
		return true
	end
end

function UserIP(nick)
	result, sIP = VH:GetUserIP(nick)
	if (string.len(sIP) < 7) then
		return 0
	else
		return sIP
	end
end

function SendEmoteToHub(data, from)
	result, err = VH:SendDataToAll("<"..from.."> ".."/me "..data.."|",0,10)
	return 1
end

function KickAllUsersWithIP(ip, reason)
	_,nicklist = VH:GetNickList()
	nicklist = string.sub(nicklist, 11)
	local flag = false
	for names in string.gmatch(nicklist, "([^%$]+)%$%$") do
		if (ip == UserIP(names)) then
			if (flag == false) then
				VH:KickUser(security, names, reason)
				flag = true
			else
				VH:CloseConnection(names)
			end
		end
	end
end
-----